#include <unittest/unittest.h>
#include <cusp/permutation_matrix.h>

template <class Space>
void TestPermutationMatrixBasicConstructor(void)
{
    cusp::permutation_matrix<int, Space> matrix(3);
    
    ASSERT_EQUAL(matrix.num_rows,              3);
    ASSERT_EQUAL(matrix.num_cols,              3);
    ASSERT_EQUAL(matrix.num_entries,           3);
    ASSERT_EQUAL(matrix.values.size(),         3);
}
DECLARE_HOST_DEVICE_UNITTEST(TestPermutationMatrixBasicConstructor);

template <class Space>
void TestPermutationMatrixCopyConstructor(void)
{
    cusp::permutation_matrix<int, Space> matrix(3);

    matrix.values[0] = 0;  matrix.values[1] = 1;  matrix.values[2] = 2;

    cusp::permutation_matrix<int, Space> copy_of_matrix(matrix);
    
    ASSERT_EQUAL(copy_of_matrix.num_rows,              3);
    ASSERT_EQUAL(copy_of_matrix.num_cols,              3);
    ASSERT_EQUAL(copy_of_matrix.num_entries,           3);
    ASSERT_EQUAL(copy_of_matrix.values.size(),         3);
   
    ASSERT_EQUAL(copy_of_matrix.values,         matrix.values);
}
DECLARE_HOST_DEVICE_UNITTEST(TestPermutationMatrixCopyConstructor);

template <class Space>
void TestPermutationMatrixResize(void)
{
    cusp::permutation_matrix<int, Space> matrix;
    
    matrix.resize(3);

    ASSERT_EQUAL(matrix.num_rows,              3);
    ASSERT_EQUAL(matrix.num_cols,              3);
    ASSERT_EQUAL(matrix.num_entries,           3);
    ASSERT_EQUAL(matrix.values.size(),         3);
}
DECLARE_HOST_DEVICE_UNITTEST(TestPermutationMatrixResize);

template <class Space>
void TestPermutationMatrixSwap(void)
{
    cusp::permutation_matrix<int, Space> A(2);
    cusp::permutation_matrix<int, Space> B(3);
  
    A.values[0] = 0;  A.values[1] = 1;
    
    B.values[0] = 0;  B.values[1] = 1;  B.values[2] = 2;
    
    cusp::permutation_matrix<int, Space> A_copy(A);
    cusp::permutation_matrix<int, Space> B_copy(B);

    A.swap(B);

    ASSERT_EQUAL(A.num_rows,              3);
    ASSERT_EQUAL(A.num_cols,              3);
    ASSERT_EQUAL(A.num_entries,           3);
    ASSERT_EQUAL(A.values,         B_copy.values);

    ASSERT_EQUAL(B.num_rows,              2);
    ASSERT_EQUAL(B.num_cols,              2);
    ASSERT_EQUAL(B.num_entries,           2);
    ASSERT_EQUAL(B.values,         A_copy.values);
}
DECLARE_HOST_DEVICE_UNITTEST(TestPermutationMatrixSwap);

void TestPermutationMatrixRebind(void)
{
    typedef cusp::permutation_matrix<int, cusp::host_memory> HostMatrix;
    typedef HostMatrix::rebind<cusp::device_memory>::type   DeviceMatrix;

    HostMatrix   h_matrix(10);
    DeviceMatrix d_matrix(h_matrix);

    ASSERT_EQUAL(h_matrix.num_entries, d_matrix.num_entries);
}
DECLARE_UNITTEST(TestPermutationMatrixRebind);

template <class Space>
void TestPermutationMatrixRandomPermutation(void)
{
    cusp::permutation_matrix<int, Space> A(5);
    
    A.random_permutation();

    thrust::sort(A.values.begin(), A.values.end());
    
    ASSERT_EQUAL(A.values[0], 0);
    ASSERT_EQUAL(A.values[1], 1);
    ASSERT_EQUAL(A.values[2], 2);
    ASSERT_EQUAL(A.values[3], 3);
    ASSERT_EQUAL(A.values[4], 4);
}
DECLARE_HOST_DEVICE_UNITTEST(TestPermutationMatrixRandomPermutation);

